package org.deng.learn.concurrent.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author 邓力宾
 * @date 2020/5/15 下午4:41
 * @desc
ReenTrantLock的字面意思就是再进入的锁，其实synchronized关键字所使用的锁也是可重入的，两者关于这个的区别不大。
 * 两者都是同一个线程没进入一次，锁的计数器都自增1，所以要等到锁的计数器下降为0时才能释放锁。
 *
 *
 * Synchronized是依赖于JVM实现的，而ReenTrantLock是JDK实现的(基于AQS)，有什么区别，说白了就类似于操作系统来控制实现和用户自己敲代码实现的区别。
 * 前者的实现是比较难见到的，后者有直接的源码可供阅读
 *
 * 在Synchronized优化以前，synchronized的性能是比ReenTrantLock差很多的，但是自从Synchronized引入了偏向锁，轻量级锁（自旋锁）后，
 * 两者的性能就差不多了
 *
 * 便利性：很明显Synchronized的使用比较方便简洁，并且由编译器去保证锁的加锁和释放，而ReenTrantLock需要手工声明来加锁和释放锁，
 * 为了避免忘记手工释放锁造成死锁，所以最好在finally中声明释放锁。
 * 锁的细粒度和灵活度：很明显ReenTrantLock优于Synchronized
 *
 * ReenTrantLock独有的能力：
1.      ReenTrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。
2.      ReenTrantLock提供了一个Condition（条件）类，用来实现分组唤醒需要唤醒的线程们，
而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。
3.      ReenTrantLock提供了一种能够中断等待锁的线程的机制，通过lock.lockInterruptibly()来实现这个机制
 */
public class ReentrantLockDemo {
    Lock lock = new ReentrantLock();
    //Lock lock = new ReentrantLock(true);置为true 是公平锁

    void m1(){
        lock.lock();
        try {
            for(int i = 0; i < 10; i++){
                Thread.sleep(1000);
                System.out.println("m1方法执行"+i);
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("被打断");
        }finally {
            lock.unlock();//必须手动释放
        }

    }

    //使用同一个锁 m1 和m2 互斥
    void  m2(){
        lock.lock();
        System.out.println("m2方法执行");
        lock.unlock();
    }

    void m3(){
        try {
            boolean isGetLock = lock.tryLock(5, TimeUnit.SECONDS); //尝试获取锁 等5秒 拿到了返回true,没拿到返回false
            if(isGetLock){
                System.out.println("m3拿到锁");
            }else{
                System.out.println("m3没拿到锁");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args){
        ReentrantLockDemo test = new ReentrantLockDemo();
        Thread t1 = new Thread(()->{test.m1();});
        t1.start();
        new Thread(test::m2).start();
        new Thread(test::m3).start();

        t1.interrupt();//t1打断
    }
}
